import sqlite3
import numpy as np
import time
from datetime import datetime, timedelta
import threading

class AIFaultDetector:
    def __init__(self):
        self.baselines = {
            'sensor1': {'mean': 25.0, 'std': 2.0, 'threshold': 3.0},
            'sensor2': {'mean': 50.0, 'std': 5.0, 'threshold': 3.0},
            'sensor3': {'mean': 5.0, 'std': 0.5, 'threshold': 3.0},
            'sensor4': {'mean': 500.0, 'std': 50.0, 'threshold': 3.0}
        }
        self.is_calibrating = False
        self.calibration_data = {}
        self.fault_history = []
        self.running = False
        self.check_interval = 5  # 检查间隔（秒）
        self.db_path = 'plc_data.db'
        
    # 启动故障检测服务
    def start(self):
        self.running = True
        self.thread = threading.Thread(target=self._detection_loop)
        self.thread.daemon = True
        self.thread.start()
        print("AI故障检测服务已启动")
        
    # 停止故障检测服务
    def stop(self):
        self.running = False
        if hasattr(self, 'thread') and self.thread.is_alive():
            self.thread.join(timeout=2.0)
        print("AI故障检测服务已停止")
        
    # 校准基线
    def calibrate_baseline(self, duration=60):
        self.is_calibrating = True
        self.calibration_data = {
            'sensor1': [], 'sensor2': [], 'sensor3': [], 'sensor4': []
        }
        
        print(f"开始校准基线，持续 {duration} 秒...")
        start_time = time.time()
        
        while time.time() - start_time < duration and self.running:
            latest_data = self._get_latest_data()
            if latest_data:
                for sensor in self.calibration_data.keys():
                    if sensor in latest_data and latest_data[sensor] is not None:
                        self.calibration_data[sensor].append(latest_data[sensor])
            time.sleep(1)
        
        # 计算新的基线
        for sensor in self.baselines.keys():
            if len(self.calibration_data[sensor]) > 0:
                data_array = np.array(self.calibration_data[sensor])
                self.baselines[sensor]['mean'] = np.mean(data_array)
                self.baselines[sensor]['std'] = np.std(data_array)
                print(f"传感器 {sensor} 校准完成: 均值={self.baselines[sensor]['mean']:.2f}, 标准差={self.baselines[sensor]['std']:.2f}")
            else:
                print(f"传感器 {sensor} 校准数据不足，保持原有基线")
        
        self.is_calibrating = False
        print("基线校准完成")
        return self.baselines
    
    # 设置基线参数
    def set_baseline(self, sensor, mean, std, threshold=3.0):
        if sensor in self.baselines:
            self.baselines[sensor] = {
                'mean': float(mean),
                'std': float(std),
                'threshold': float(threshold)
            }
            print(f"传感器 {sensor} 基线已更新: 均值={mean}, 标准差={std}, 阈值={threshold}")
            return True
        return False
    
    # 获取基线参数
    def get_baselines(self):
        return self.baselines
    
    # 获取最新故障
    def get_latest_fault(self):
        if self.fault_history:
            return self.fault_history[-1]
        return None
    
    # 获取故障历史
    def get_fault_history(self, limit=10):
        return self.fault_history[-limit:]
    
    # 检测循环
    def _detection_loop(self):
        while self.running:
            try:
                # 获取最新数据
                latest_data = self._get_latest_data()
                if latest_data and not self.is_calibrating:
                    # 执行故障检测
                    faults = self._detect_faults(latest_data)
                    if faults:
                        fault_info = {
                            'timestamp': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
                            'data': latest_data,
                            'faults': faults
                        }
                        self.fault_history.append(fault_info)
                        # 限制历史记录大小
                        if len(self.fault_history) > 1000:
                            self.fault_history = self.fault_history[-1000:]
                        
                        print(f"检测到故障: {fault_info}")
            except Exception as e:
                print(f"故障检测异常: {e}")
            
            # 等待下一次检查
            wait_time = self.check_interval
            while wait_time > 0 and self.running:
                time.sleep(0.1)
                wait_time -= 0.1
    
    # 从数据库获取最新数据
    def _get_latest_data(self):
        try:
            conn = sqlite3.connect(self.db_path)
            cursor = conn.cursor()
            cursor.execute("SELECT timestamp, sensor1, sensor2, sensor3, sensor4 FROM plc_data ORDER BY timestamp DESC LIMIT 1")
            row = cursor.fetchone()
            conn.close()
            
            if row:
                return {
                    'timestamp': row[0],
                    'sensor1': row[1],
                    'sensor2': row[2],
                    'sensor3': row[3],
                    'sensor4': row[4]
                }
            return None
        except Exception as e:
            print(f"获取数据异常: {e}")
            return None
    
    # 故障检测算法
    def _detect_faults(self, data):
        faults = []
        
        # 基于统计学的异常检测
        for sensor, baseline in self.baselines.items():
            if sensor in data and data[sensor] is not None:
                value = data[sensor]
                mean = baseline['mean']
                std = baseline['std']
                threshold = baseline['threshold']
                
                # 计算Z-score
                if std > 0:
                    z_score = abs(value - mean) / std
                    if z_score > threshold:
                        faults.append({
                            'type': 'statistical_anomaly',
                            'sensor': sensor,
                            'value': value,
                            'mean': mean,
                            'std': std,
                            'z_score': z_score,
                            'message': f"传感器 {sensor} 读数异常 (Z-score: {z_score:.2f})"
                        })
                
                # 检查是否在合理范围内
                if sensor == 'sensor1':  # 假设是温度传感器
                    if value < 0 or value > 100:
                        faults.append({
                            'type': 'range_exceeded',
                            'sensor': sensor,
                            'value': value,
                            'message': f"温度传感器超出正常范围 (0-100°C)"
                        })
                elif sensor == 'sensor2':  # 假设是湿度传感器
                    if value < 0 or value > 100:
                        faults.append({
                            'type': 'range_exceeded',
                            'sensor': sensor,
                            'value': value,
                            'message': f"湿度传感器超出正常范围 (0-100%)"
                        })
                elif sensor == 'sensor3':  # 假设是电压传感器
                    if value < 0 or value > 24:
                        faults.append({
                            'type': 'range_exceeded',
                            'sensor': sensor,
                            'value': value,
                            'message': f"电压传感器超出正常范围 (0-24V)"
                        })
                elif sensor == 'sensor4':  # 假设是气体传感器
                    if value < 0 or value > 2000:
                        faults.append({
                            'type': 'range_exceeded',
                            'sensor': sensor,
                            'value': value,
                            'message': f"气体传感器超出正常范围 (0-2000PPM)"
                        })
        
        # 传感器间相关性分析
        if len(faults) == 0:
            # 检查温度和湿度是否有合理的相关性
            if 'sensor1' in data and 'sensor2' in data and data['sensor1'] is not None and data['sensor2'] is not None:
                temp = data['sensor1']
                humidity = data['sensor2']
                
                # 简单的相关性检查（实际应用中可以使用更复杂的模型）
                expected_humidity_low = max(0, 80 - 0.5 * temp)  # 温度升高，湿度通常降低
                expected_humidity_high = min(100, 95 - 0.2 * temp)
                
                if humidity < expected_humidity_low or humidity > expected_humidity_high:
                    faults.append({
                        'type': 'correlation_anomaly',
                        'sensors': ['sensor1', 'sensor2'],
                        'values': [temp, humidity],
                        'message': f"温度和湿度相关性异常 (温度={temp}°C, 湿度={humidity}%)"
                    })
        
        return faults
    
    # 趋势分析
    def analyze_trend(self, sensor, time_window=60):
        try:
            # 计算时间窗口
            end_time = datetime.now()
            start_time = end_time - timedelta(seconds=time_window)
            
            conn = sqlite3.connect(self.db_path)
            cursor = conn.cursor()
            cursor.execute(
                "SELECT timestamp, " + sensor + " FROM plc_data WHERE timestamp BETWEEN ? AND ? ORDER BY timestamp ASC",
                (start_time.strftime('%Y-%m-%d %H:%M:%S'), end_time.strftime('%Y-%m-%d %H:%M:%S'))
            )
            rows = cursor.fetchall()
            conn.close()
            
            if len(rows) < 5:
                return None  # 数据点太少，无法分析趋势
            
            # 提取数据
            values = []
            timestamps = []
            for row in rows:
                if row[1] is not None:
                    values.append(row[1])
                    timestamps.append(datetime.strptime(row[0], '%Y-%m-%d %H:%M:%S'))
            
            if len(values) < 5:
                return None
            
            # 计算时间差值（分钟）作为x轴
            x = [(t - timestamps[0]).total_seconds() / 60 for t in timestamps]
            y = values
            
            # 线性回归分析趋势
            slope, intercept = np.polyfit(x, y, 1)
            
            # 计算R²值评估拟合质量
            y_pred = [slope * xi + intercept for xi in x]
            ss_total = np.sum((y - np.mean(y)) ** 2)
            ss_residual = np.sum((y - y_pred) ** 2)
            r_squared = 1 - (ss_residual / ss_total) if ss_total > 0 else 0
            
            # 确定趋势方向和强度
            trend_direction = 'stable'
            trend_strength = 'weak'
            
            # 计算标准差用于确定阈值
            std_value = np.std(y)
            
            # 确定趋势方向
            if abs(slope) > 0.1 * std_value / (time_window / 60):  # 根据时间窗口调整阈值
                if slope > 0:
                    trend_direction = 'rising'
                else:
                    trend_direction = 'falling'
            
            # 确定趋势强度
            if abs(slope) > 0.3 * std_value / (time_window / 60):
                trend_strength = 'strong'
            elif abs(slope) > 0.1 * std_value / (time_window / 60):
                trend_strength = 'moderate'
            
            return {
                'sensor': sensor,
                'time_window': time_window,
                'data_points': len(values),
                'slope': slope,
                'r_squared': r_squared,
                'trend_direction': trend_direction,
                'trend_strength': trend_strength,
                'message': f"传感器 {sensor} 在过去 {time_window} 秒呈现 {trend_strength} {trend_direction} 趋势"
            }
        except Exception as e:
            print(f"趋势分析异常: {e}")
            return None

# 测试代码
if __name__ == '__main__':
    detector = AIFaultDetector()
    detector.start()
    
    try:
        print("AI故障检测器运行中，按Ctrl+C停止...")
        time.sleep(10)  # 等待一段时间收集数据
        
        # 测试校准功能
        print("\n执行基线校准...")
        # detector.calibrate_baseline(duration=10)
        
        # 测试趋势分析
        print("\n执行趋势分析...")
        for sensor in ['sensor1', 'sensor2', 'sensor3', 'sensor4']:
            trend = detector.analyze_trend(sensor)
            if trend:
                print(f"{sensor} 趋势分析: {trend['message']}")
        
        # 保持程序运行
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        print("\n正在停止AI故障检测器...")
        detector.stop()
        print("AI故障检测器已停止")